using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Fusion8Design.Win32;

namespace ScreenSnapper
{
    public partial class BlankForm : Form
    {
        private Image _backgroundImage = null;
        private Image _selectedImage = null;
        private bool _mouseDown;
        private bool _mouseHasMoved;
        private Point _backgroundTopLeft = new Point();
        private Point _mouseStart = new Point();
        private Point _mouseLastEnd = new Point();
        private Point _mouseEnd = new Point();
        private Point _mousePos = new Point();
        private Pen _rectPen = new Pen(Color.BlueViolet);
        private const int MAGNIFY_SIZE = 100;
        private Rectangle _magnifyRect = new Rectangle(50, 50, MAGNIFY_SIZE, MAGNIFY_SIZE);

        private int MinX { get; set; }
        private int MinY { get; set; }
        private int MaxX { get; set; }
        private int MaxY { get; set; }

        public Image SelectedImage
        {
            get
            {
                return _selectedImage;
            }
        }

        public Point TopLeft
        {
            get
            {
                int x = Math.Min(_mouseStart.X, _mouseEnd.X);
                int y = Math.Min(_mouseStart.Y, _mouseEnd.Y);

                return new Point(x + Location.X, y + Location.Y);
            }
        }

        public BlankForm()
        {
            InitializeComponent();

            _mouseDown = false;

            Screen[] screens = Screen.AllScreens;

            MinX = int.MaxValue;
            MinY = int.MaxValue;
            MaxX = int.MinValue;
            MaxY = int.MinValue;

            for (int i = 0; i < screens.Length; ++i)
            {
                Rectangle bounds = screens[i].Bounds;
                if (bounds.Left < MinX)
                    MinX = bounds.Left;
                if (bounds.Right > MaxX)
                    MaxX = bounds.Right;
                if (bounds.Top < MinY)
                    MinY = bounds.Top;
                if (bounds.Bottom > MaxY)
                    MaxY = bounds.Bottom;
            }

            int screenWidth = (MaxX - MinX); //Screen.PrimaryScreen.Bounds.Width;
            int screenHeight = (MaxY - MinY); //Screen.PrimaryScreen.Bounds.Height;

            _backgroundTopLeft = new Point(0, 0);//new Point(minX, minY);
            ClientSize = new Size(screenWidth, screenHeight);
            Location = new Point(MinX, MinY);

            _backgroundImage = Desktop.GetBitmap(MinX, MinY, screenWidth, screenHeight);
        }

        private Font _font;
        private Font SizeFont
        {
            get
            {
                if (_font == null)
                {
                    _font = new Font("Courier New", 10f, FontStyle.Bold);
                }
                return _font;
            }
        }

        private StringFormat _sizeFormat;
        private StringFormat SizeFormat
        {
            get
            {
                if (_sizeFormat == null)
                {
                    _sizeFormat = new StringFormat();
                    _sizeFormat.Alignment = StringAlignment.Center;
                }
                return _sizeFormat;
            }
        }

        private void BlankForm_Paint(object sender, PaintEventArgs e)
        {
            if (null != _backgroundImage)
            {
                RectangleF srcRect = new RectangleF(-3.5f+_mousePos.X, -3.5f+_mousePos.Y, 7f, 7f);

                if (srcRect.Left < _backgroundTopLeft.X)
                    srcRect.Offset(_backgroundTopLeft.X - srcRect.Left, 0);
                if (srcRect.Top < _backgroundTopLeft.Y)
                    srcRect.Offset(0, _backgroundTopLeft.Y - srcRect.Top);

                e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
                e.Graphics.DrawImageUnscaled(_backgroundImage, _backgroundTopLeft);
                e.Graphics.DrawLine(Pens.DarkGray, 0, _mousePos.Y, (MaxX - MinX), _mousePos.Y);
                e.Graphics.DrawLine(Pens.DarkGray, _mousePos.X, 0, _mousePos.X, (MaxY - MinY));
                e.Graphics.DrawImage(_backgroundImage, _magnifyRect, srcRect, GraphicsUnit.Pixel);
                e.Graphics.DrawRectangle(_rectPen, _magnifyRect.Left, _magnifyRect.Top, _magnifyRect.Width - 1, _magnifyRect.Height - 1);
            }


            if (_mouseDown && _mouseHasMoved)
            {
                int x1 = Math.Min(_mouseStart.X, _mouseEnd.X);
                int x2 = Math.Max(_mouseStart.X, _mouseEnd.X);
                int y1 = Math.Min(_mouseStart.Y, _mouseEnd.Y);
                int y2 = Math.Max(_mouseStart.Y, _mouseEnd.Y);

                e.Graphics.DrawRectangle(_rectPen, x1, y1, x2-x1, y2-y1);

                int w = Math.Abs(x2 - x1);
                int h = Math.Abs(y2 - y1);

                var textRect = new RectangleF(_magnifyRect.Left, _magnifyRect.Bottom + 3, _magnifyRect.Width, 20);
                e.Graphics.FillRectangle(Brushes.White, textRect);
                e.Graphics.DrawString(string.Format("{0} x {1}", w, h), SizeFont, Brushes.Black, textRect, SizeFormat);
            }
        }

        private void BlankForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode.Equals(Keys.Escape))
            {
                Close();
            }
        }

        private void BlankForm_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                _mouseDown = true;
                _mouseHasMoved = false;
                _mouseStart.X = e.Location.X;
                _mouseStart.Y = e.Location.Y;
            }
            else if (e.Button == MouseButtons.Right)
            {
                _mouseStart.X = 0;
                _mouseStart.Y = 0;
                _mouseEnd.X = Screen.PrimaryScreen.Bounds.Width;
                _mouseEnd.Y = Screen.PrimaryScreen.Bounds.Height;

                InitSelectedImage();
            }
        }

        private void BlankForm_MouseUp(object sender, MouseEventArgs e)
        {
            if (_mouseDown)
            {
                _mouseDown = false;
                _mouseEnd.X = e.Location.X;
                _mouseEnd.Y = e.Location.Y;

                // Force a redraw
                Refresh();

                InitSelectedImage();
            }
        }

        private void BlankForm_MouseMove(object sender, MouseEventArgs e)
        {
            var lastPos = _mousePos;
            _mousePos.X = e.Location.X;
            _mousePos.Y = e.Location.Y;

            if (_magnifyRect.Contains(_mousePos.X, _mousePos.Y))
            {
                Invalidate(_magnifyRect);
                if (_magnifyRect.Left < 100)
                    _magnifyRect.Offset(MAGNIFY_SIZE + 10, 0);
                else
                    _magnifyRect.Offset(-(MAGNIFY_SIZE + 10), 0);
            }

            if (_mouseDown)
            {
                if (_mouseHasMoved)
                {
                    if (_mouseLastEnd.Equals(e.Location))
                        return;

                    _mouseLastEnd.X = _mouseEnd.X;
                    _mouseLastEnd.Y = _mouseEnd.Y;
                }

                _mouseEnd.X = e.Location.X;
                _mouseEnd.Y = e.Location.Y;

                if (_mouseHasMoved)
                {
                    int invX1 = Math.Min(_mouseLastEnd.X, Math.Min(_mouseStart.X, _mouseEnd.X)) - 1;
                    //invX1 = invX1 < 0 ? 0 : invX1;
                    int invX2 = Math.Max(_mouseLastEnd.X, Math.Max(_mouseStart.X, _mouseEnd.X)) + 1;
                    int invY1 = Math.Min(_mouseLastEnd.Y, Math.Min(_mouseStart.Y, _mouseEnd.Y)) - 1;
                    //invY1 = invY1 < 0 ? 0 : invY1;
                    int invY2 = Math.Max(_mouseLastEnd.Y, Math.Max(_mouseStart.Y, _mouseEnd.Y)) + 1;

                    Invalidate(new Rectangle(invX1, invY1, invX2 - invX1, invY2 - invY1));
                    Invalidate(new Rectangle(_magnifyRect.Left, _magnifyRect.Bottom, _magnifyRect.Width, 30));
                }

                _mouseHasMoved = true;
            }

            if (lastPos != e.Location)
            {
                // Haircross
                int minX = Math.Min(lastPos.X, e.Location.X);
                int minY = Math.Min(lastPos.Y, e.Location.Y);
                int maxX = Math.Max(lastPos.X, e.Location.X);
                int maxY = Math.Max(lastPos.Y, e.Location.Y);

                Invalidate(new Rectangle(0, minY, (MaxX - MinX), maxY));
                Invalidate(new Rectangle(minX, 0, maxX, (MaxY - MinY)));
            }

            Invalidate(_magnifyRect);
        }

        private void InitSelectedImage()
        {
            int width = Math.Abs(_mouseStart.X - _mouseEnd.X);
            int height = Math.Abs(_mouseStart.Y - _mouseEnd.Y);

            if (width == 0 || height == 0)
                return;

            width++;
            height++;

            int x1 = Math.Min(_mouseStart.X, _mouseEnd.X);
            int y1 = Math.Min(_mouseStart.Y, _mouseEnd.Y);

            Rectangle sourceRect = new Rectangle(x1, y1, width, height);

            Bitmap selectedImage = new Bitmap(width, height);
            Graphics g = Graphics.FromImage(selectedImage);
            g.DrawImage(_backgroundImage, 0, 0, sourceRect, GraphicsUnit.Pixel);
            g.Dispose();

            _selectedImage = selectedImage;

            _backgroundImage.Dispose();
            _backgroundImage = null;

            Close();
        }
    }
}